﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using System.Data.SqlClient;
using System.Threading;

namespace Hp.Vertica.Migration.SqlServer
{
    public class ServerInstance
    {
        public String DataSource { get; private set; }
        public Boolean IntegratedSecurity { get; private set; }

        private String _user;
        public String User
        {
            get
            {
                if (IntegratedSecurity)
                {
                    return Thread.CurrentPrincipal.Identity.Name;
                }
                else
                {
                    return _user;
                }
            }
            private set
            {
                this._user = value;
            }
        }
        public String Password { get; private set; }

        public ServerInstance(String ds)
        {
            if (ds == null)
            {
                throw new ArgumentNullException();
            }
            SqlConnectionStringBuilder sb = new SqlConnectionStringBuilder();
            sb.DataSource = this.DataSource = ds;
            sb.IntegratedSecurity = this.IntegratedSecurity = true;

            this.ConnectionString = sb.ToString();
        }

        public ServerInstance(String ds, String user, String pwd)
        {
            if (ds == null || user == null || pwd == null)
            {
                throw new ArgumentNullException();
            }
            SqlConnectionStringBuilder sb = new SqlConnectionStringBuilder();
            sb.DataSource = this.DataSource = ds;
            sb.IntegratedSecurity = this.IntegratedSecurity = false;
            sb.UserID = this.User = user;
            sb.Password = this.Password = pwd;

            this.ConnectionString = sb.ToString();
        }

        public void Connect()
        {
            using (SqlConnection conn = new SqlConnection(this.ConnectionString))
            {
                conn.Open();
                Thread.Sleep(2000);
                conn.Close();
            }
        }

        public String ConnectionString { get; private set; }

        private Dictionary<String, Database> _databaseCache;

        public void Refresh()
        {
            Dictionary<String, Database> current = new Dictionary<string, Database>();
            using (SqlConnection conn = new SqlConnection(this.ConnectionString))
            {
                conn.Open();
                foreach (DataRow dr in conn.GetSchema("Databases").Rows)
                {
                    String dbName = dr["database_name"].ToString();
                    String key = dbName.ToUpper();
                    if (this._databaseCache != null && this._databaseCache.ContainsKey(key))
                    {
                        current.Add(key, this._databaseCache[key]);
                    }
                    else
                    {
                        current.Add(key, new Database(dbName, this));
                    }
                }
                conn.Close();
            }
            this._databaseCache = current;
        }

        public List<Database> Databases
        {
            get
            {
                if (this._databaseCache == null)
                {
                    this.Refresh();
                }
                return this._databaseCache.Values.OrderBy(c => c.Name).ToList();
            }
        }

        public override string ToString()
        {
            return this.DataSource + "(" + this.User + ")";
        }

        public override int GetHashCode()
        {
            return this.DataSource.GetHashCode() + this.IntegratedSecurity.GetHashCode() * 17 + this.User.GetHashCode() * 17 * 17 + this.Password.GetHashCode() * 17 * 17 * 17;
        }

        public int ExecuteScript(String script, String db)
        {
            int result;
            using (SqlConnection conn = new SqlConnection(this.ConnectionString))
            {
                conn.Open();
                if (db != null)
                {
                    conn.ChangeDatabase(db);
                }
                var cmd = conn.CreateCommand();
                cmd.CommandText = script;
                result = cmd.ExecuteNonQuery();
                conn.Close();
            }
            return result;
        }

        public int ExecuteScript(String script)
        {
            return this.ExecuteScript(script, null);
        }

    }
}
